﻿#include "OneKeyboard.h"
#include "HDBase/DPair.hpp"
#include "HDCore/DGlobal.h"
#include "HDQt/HDWidget/DToast.hpp"
#include "KeyButton.h"
#include "MouseLabel.h"
#include <QDateTime>
#include <QDebug>
#include <QMouseEvent>
#include "QStatisticsWidget.h"
#include <QTimer>
#include "OneKeyboardStruct.h"

// 每个tab页下标对应的键盘类型
const static DMap<int, DPair<KeyboardType, QString>> CSMAP_TAB_INDEX_TYPE =
{
	{ 0, DPair(LOGI_K98M, QString("罗技 K98M")) }
};


OneKeyboard::OneKeyboard(QWidget *parent)
    : QWidget(parent, Qt::FramelessWindowHint)
	, currentTimeType_(Day)
	, currentDate_(QDate::currentDate())
	, maxKeyBtn_(nullptr)
	, maxKeyCount_(0)
	, isPressed_(false)
{
    ui.setupUi(this);
	setWindowIcon(QIcon(":icon.ico"));

	// 默认显示当天数据
	auto data = generateData(currentTimeType_, currentDate_);
	refreshValues(data);

	ui.btn_bar->resetButtons(SwitchBtnBar::Hor, { DPair(tr("本次计数"), QVariant(Current))
		, DPair(tr("按天"), QVariant(Day))
		, DPair(tr("按周"), QVariant(Week))
		, DPair(tr("按月"), QVariant(Month))
		, DPair(tr("按年"), QVariant(Year)) });
	connect(ui.btn_bar, &SwitchBtnBar::sigBtnChanged, this, &OneKeyboard::slotBtnBarChanged);
	ui.btn_bar->setCurrentButton(1);

	QList<KeyButton*> buttons = ui.tab_key->findChildren<KeyButton*>();
	for (KeyButton* button : buttons)
	{
		// 连接按钮的clicked信号到槽函数
		connect(button, &QPushButton::clicked, this, &OneKeyboard::slotButtonClicked);
	}

	initMap();

	for (int i = 0; i < ui.tab_key->count(); ++i)
		ui.tab_key->setTabText(i, CSMAP_TAB_INDEX_TYPE.value(i).second);

	// 每半小时保存一次数据，防止意外情况导致电脑重启蓝屏等丢失数据
	QTimer* saveTimer = new QTimer(this);
	saveTimer->setTimerType(Qt::VeryCoarseTimer);
	connect(saveTimer, &QTimer::timeout, DATA_HANDLER, &DataHandler::syncToFile);
	saveTimer->start(1000 * 60 * 30);

	// 每天零点保存数据并重置
	QTimer* timer = new QTimer(this);
	timer->setTimerType(Qt::PreciseTimer);
	connect(timer, &QTimer::timeout, this, &OneKeyboard::slotDayNext);

	// 距离下一次零点还有多久
	QDateTime currentDT = QDateTime::currentDateTime();
	QDateTime next0 = currentDT.addDays(1);
	next0.setTime(QTime(0, 0, 0, 0));
	qint64 ms = currentDT.msecsTo(next0);
	QTimer::singleShot(ms, Qt::PreciseTimer, [this, timer]()
	{
		timer->start(1000 * 3600 * 24);
		slotDayNext();
	});
}

void OneKeyboard::show()
{
	auto data = generateData(currentTimeType_, currentDate_);
	refreshAll(data);
	QWidget::show();
}

void OneKeyboard::doBeforeExit()
{
	//DataHandler::Data newDataToday = DATA_HANDLER->getDataToday() + dataCurrent_;
	//DATA_HANDLER->setDataToday(newDataToday);
	DATA_HANDLER->syncToFile();
}

void OneKeyboard::slotKeyPressed(const KeyInfo& info)
{
	//qDebug() << __FUNCTION__ << info.key;
	DList<QString> keyNames = mapKeyNames_.value(info.key);
	for (const QString& keyName : keyNames)
	{
		QList<KeyButton*> btns = ui.tab_key->findChildren<KeyButton*>(keyName);
		if (btns.isEmpty())
			continue;

		KeyButton* btn = btns.first();
		if (nullptr == btn)
			continue;

		newKeyClicked(btn);
	}
}

void OneKeyboard::slotMousePressed(const MouseInfo& info)
{
	//qDebug() << __FUNCTION__ << info.key;
	DataHandler::Data dataToday = DATA_HANDLER->getDataToday();

	switch (info.key)
	{
	case WM_LBUTTONDOWN:
		++dataCurrent_.mLeft;
		++dataToday.mLeft;
		break;
	case WM_RBUTTONDOWN:
		++dataCurrent_.mRight;
		++dataToday.mRight;
		break;
	case WM_MBUTTONDOWN:
		++dataCurrent_.mMid;
		++dataToday.mMid;
		break;
	}

	DATA_HANDLER->setDataToday(dataToday);
	DataHandler::Data data = generateData(currentTimeType_, currentDate_);
	if (!isHidden() && todayIsInTime(currentTimeType_, currentDate_))
	{
		refreshMouse(data);
		refreshStatWidget();
	}
}

void OneKeyboard::slotButtonClicked()
{
	KeyButton* button = qobject_cast<KeyButton*>(sender());
	if (nullptr == button)
	{
		qDebug() << __FUNCTION__ << "button is nullptr!";
		return;
	}

	newKeyClicked(button);

	//QString btnName = button->objectName();
	//KeyboardType keyBoardType = CSMAP_TAB_INDEX_TYPE.value(ui.tab_key->currentIndex(), LOGI_K98M);
	//DMap<QString, DList<int>> keyMap = CSMAP_KEYBOARD_NUM.value(keyBoardType);
	//for (int i : keyMap.value(btnName))
	//	qDebug() << "kkkk:" << i;
}

void OneKeyboard::slotBtnBarChanged(QPushButton* btn, QVariant data)
{
	ui.btn_reset_key->hide();
	ui.btn_reset_mouse->hide();
	ui.btn_prev_day->hide();
	ui.btn_next_day->hide();
	ui.btn_prev_week->hide();
	ui.btn_next_week->hide();
	ui.btn_prev_month->hide();
	ui.btn_next_month->hide();
	ui.btn_prev_year->show();
	ui.btn_next_year->show();

	currentDate_ = QDate::currentDate();
	currentTimeType_ = (TimeType)data.toInt();
	switch (currentTimeType_)
	{
	case Current:  // 本次计数
		ui.btn_reset_key->show();
		ui.btn_reset_mouse->show();
		ui.btn_prev_year->hide();
		ui.btn_next_year->hide();
		break;
	case Day:  // 按天
	{
		ui.btn_prev_day->show();
		ui.btn_next_day->show();
		ui.btn_prev_month->show();
		ui.btn_next_month->show();
		break;
	}
	case Week:  // 按周
	{
		QDate today = QDate::currentDate();
		int dayOfWeek = today.dayOfWeek();
		QDate monday = today.addDays(1 - dayOfWeek);
		for (int i = 0; i < 7; ++i)
		{
			QDate date = monday.addDays(i);
			//dataShowing_ += DATA_HANDLER->getData(date);
		}
		ui.btn_prev_week->show();
		ui.btn_next_week->show();
		break;
	}
	case Month:  // 按月
	{
		ui.btn_prev_month->show();
		ui.btn_next_month->show();
		break;
	}
	case Year:  // 按年
	{
		break;
	}
	}
	auto dData = generateData(currentTimeType_, currentDate_);
	refreshAll(dData);
}

void OneKeyboard::on_tab_key_currentChanged(int index)
{
	initMap();
}

void OneKeyboard::on_btn_prev_day_clicked()
{
	currentDate_ = currentDate_.addDays(-1);
	auto data = generateData(currentTimeType_, currentDate_);
	refreshAll(data);
}

void OneKeyboard::on_btn_next_day_clicked()
{
	currentDate_ = currentDate_.addDays(1);
	auto data = generateData(currentTimeType_, currentDate_);
	refreshAll(data);
}

void OneKeyboard::on_btn_prev_week_clicked()
{
	currentDate_ = currentDate_.addDays(-7);
	auto data = generateData(currentTimeType_, currentDate_);
	refreshAll(data);
}

void OneKeyboard::on_btn_next_week_clicked()
{
	currentDate_ = currentDate_.addDays(7);
	auto data = generateData(currentTimeType_, currentDate_);
	refreshAll(data);
}

void OneKeyboard::on_btn_prev_month_clicked()
{
	currentDate_ = currentDate_.addMonths(-1);
	auto data = generateData(currentTimeType_, currentDate_);
	refreshAll(data);
}

void OneKeyboard::on_btn_next_month_clicked()
{
	currentDate_ = currentDate_.addMonths(1);
	auto data = generateData(currentTimeType_, currentDate_);
	refreshAll(data);
}

void OneKeyboard::on_btn_prev_year_clicked()
{
	currentDate_ = currentDate_.addYears(-1);
	auto data = generateData(currentTimeType_, currentDate_);
	refreshAll(data);
}

void OneKeyboard::on_btn_next_year_clicked()
{
	currentDate_ = currentDate_.addYears(1);
	auto data = generateData(currentTimeType_, currentDate_);
	refreshAll(data);
}

void OneKeyboard::on_btn_reset_key_clicked()
{
	if (currentTimeType_ != Current)
	{
		DToast::toast(tr("只有 当前计数 模式下才能重置！"));
		return;
	}

	dataCurrent_.resetKey();
	maxKeyCount_ = 0;
	maxKeyBtn_ = nullptr;
	totalCount_ = 0;
	if (!isHidden())
	{
		refreshKey(dataCurrent_);
		refreshKeyText();
	}
}

void OneKeyboard::on_btn_reset_mouse_clicked()
{
	if (currentTimeType_ != Current)
	{
		DToast::toast(tr("只有 当前计数 模式下才能重置！"));
		return;
	}

	dataCurrent_.resetMouse();
	if (!isHidden())
		refreshMouse(dataCurrent_);
}

void OneKeyboard::on_btn_hide_clicked()
{
	hide();
}

void OneKeyboard::initMap()
{
	mapKeyNames_.clear();
	KeyboardType keyBoardType = CSMAP_TAB_INDEX_TYPE.value(ui.tab_key->currentIndex()).first;
	DMap<QString, DList<int>> keyMap = CSMAP_KEYBOARD_NUM.value(keyBoardType);

	for (auto it = keyMap.cbegin(); it != keyMap.cend(); ++it)
	{
		for (int i : *it)
			mapKeyNames_[i].pushBack(it.key());
	}
}

void OneKeyboard::refreshAll(const DataHandler::Data& data)
{
	refreshValues(data);
	refreshKey(data);
	refreshKeyText();
	refreshMouse(data);
	refreshLabelDate();
	refreshStatWidget();
}

// 刷新每一个按钮的颜色
void OneKeyboard::refreshKey(const DataHandler::Data& data)
{
	// count开根号后，每份多少颜色值
	double per = maxKeyCount_ == 0 ? 0 : (255 / std::pow(maxKeyCount_ * 1.0, COLOR_POW_NUM));
	QList<KeyButton*> buttons = ui.tab_key->findChildren<KeyButton*>();
	for (KeyButton* btn : buttons)
	{
		if (nullptr == btn)
			continue;
		int count = data.keys.value(btn->objectName());
		int colorValue = dRound(std::pow(count * 1.0, COLOR_POW_NUM) * per);
		btn->setToolTip(QString::number(count));
		btn->setStyleSheet(QString("background-color: rgb(255, %1, %1);").arg(255 - colorValue));
	}
}

void OneKeyboard::refreshMouse(const DataHandler::Data& data)
{
	ui.label_mouse->refreshColor(data);
	ui.label_mouse2->setText(tr("鼠标总按键次数：%1")
		.arg(data.getMouseTotal()));
	ui.label_mouse3->setText(tr("左键次数：%1    右键次数：%2    中键次数：%3")
		.arg(data.mLeft).arg(data.mRight).arg(data.mMid));
}

void OneKeyboard::refreshKeyText()
{
	ui.label_key1->setText(tr("键盘总按键次数：%1").arg(totalCount_));
	if (nullptr != maxKeyBtn_)
		ui.label_key2->setText(tr("最多按键：%2    次数：%3")
			.arg(maxKeyBtn_->text().trimmed().replace('\n', " / ")).arg(maxKeyCount_));
}

void OneKeyboard::refreshLabelDate()
{
	switch (currentTimeType_)
	{
	case Current:
		ui.label_date->setText(tr("本次计数"));
		break;
	case Day:
		ui.label_date->setText(currentDate_.toString(tr("yyyy年MM月dd日")));
		break;
	case Week:
	{
		int year = 0;
		int week = currentDate_.weekNumber(&year);
		ui.label_date->setText(tr("%1年%2周").arg(year).arg(week));
		break;
	}
	case Month:
		ui.label_date->setText(currentDate_.toString(tr("yyyy年MM月")));
		break;
	case Year:
		ui.label_date->setText(currentDate_.toString(tr("yyyy年")));
		break;
	default:
		break;
	}
}

void OneKeyboard::refreshStatWidget()
{
	if (currentTimeType_ == Current)
	{
		ui.stat_mouse->setVisible(false);
		ui.stat_key->setVisible(false);
		return;
	}
	
	ui.stat_mouse->setVisible(true);
	ui.stat_key->setVisible(true);

	// 往前数20个
	QDate date = currentDate_;
	DList<StatisticsNode> mouseDatas;
	DList<StatisticsNode> keyDatas;
	for (int i = 0; i < 20; ++i)
	{
		QString name;
		DataHandler::Data data;
		switch (currentTimeType_)
		{
		case Day:
			name = tr("%1日").arg(date.day());
			data = DATA_HANDLER->getData(date);
			date = date.addDays(-1);
			break;
		case Week:
		{
			name = tr("%1周").arg(date.weekNumber());
			QDate monday = date.addDays(1 - date.dayOfWeek());
			for (int i = 0; i < 7; ++i)
				data += DATA_HANDLER->getData(monday.addDays(i));
			date = date.addDays(-7);
			break;
		}
		case Month:
			name = tr("%1月").arg(date.month());
			data = DATA_HANDLER->getData(date.year(), date.month());
			date = date.addMonths(-1);
			break;
		case Year:
			name = tr("%1年").arg(date.year());
			data = DATA_HANDLER->getData(date.year());
			date = date.addYears(-1);
			break;
		default:
			qWarning() << __FUNCTION__ << "error type:" << currentTimeType_;
			return;
		}

		StatisticsNode mouseNode;
		int mouseTotal = data.getMouseTotal();
		mouseNode.value = getTransValue(mouseTotal);
		mouseNode.valueName = QString::number(mouseTotal);
		mouseNode.name = name;
		mouseDatas.pushFront(mouseNode);

		StatisticsNode keyNode;
		int keyTotal = data.getKeyTotal();
		keyNode.value = getTransValue(keyTotal);
		keyNode.valueName = QString::number(keyTotal);
		keyNode.name = name;
		keyDatas.pushFront(keyNode);
	}

	ui.stat_mouse->setData(mouseDatas);
	ui.stat_key->setData(keyDatas);
}

void OneKeyboard::newKeyClicked(KeyButton* btn)
{
	QString btnName = btn->objectName();

	// 修改本次计数
	int nowCount = dataCurrent_.keys.value(btnName);
	++nowCount;
	dataCurrent_.keys.insert(btnName, nowCount);

	// 修改今天计数
	auto todayData = DATA_HANDLER->getDataToday();
	int todayCount = todayData.keys.value(btnName);
	++todayCount;
	todayData.keys.insert(btnName, todayCount);
	DATA_HANDLER->setDataToday(todayData);

	if (!todayIsInTime(currentTimeType_, currentDate_))
		return;

	++totalCount_;

	// 获取maxCount
	if (Current != currentTimeType_)
		nowCount = generateData(currentTimeType_, currentDate_).keys.value(btnName);

	if (nowCount > maxKeyCount_)
	{
		maxKeyCount_ = nowCount;
		maxKeyBtn_ = btn;
		if (!isHidden() && todayIsInTime(currentTimeType_, currentDate_))
		{
			DataHandler::Data data = generateData(currentTimeType_, currentDate_);
			refreshKey(data);
		}
	}
	else
	{
		double per = maxKeyCount_ == 0 ? 0 : (255 / std::pow(maxKeyCount_ * 1.0, COLOR_POW_NUM));
		double colorValue = std::pow(nowCount * 1.0, COLOR_POW_NUM) * per;
		btn->setStyleSheet(QString("background-color: rgb(255, %1, %1);").arg(dRound(255 - colorValue)));
	}
	if (!isHidden() && todayIsInTime(currentTimeType_, currentDate_))
	{
		refreshKeyText();
		refreshStatWidget();
	}
}

void OneKeyboard::slotDayNext()
{
	//DataHandler::Data newDataToday = DATA_HANDLER->getDataToday() + dataCurrent_;
	//DATA_HANDLER->setDataToday(newDataToday);
	DATA_HANDLER->syncToFile();
	on_btn_reset_key_clicked();
	on_btn_reset_mouse_clicked();
}

void OneKeyboard::refreshValues(const DataHandler::Data& data)
{
	auto maxPair = data.getKeyMax();
	QList<KeyButton*> l = ui.tab_key->findChildren<KeyButton*>(maxPair.first);
	if (!l.isEmpty())
	{
		maxKeyBtn_ = l.first();
		maxKeyCount_ = maxPair.second;
	}
	totalCount_ = data.getKeyTotal();
}

DataHandler::Data OneKeyboard::generateData(TimeType type, const QDate& date)
{
	switch (currentTimeType_)
	{
	case Current:
		return dataCurrent_;
	case Day:
		return DATA_HANDLER->getData(date);
	case Week:
	{
		DataHandler::Data data;
		QDate monday = date.addDays(1 - date.dayOfWeek());
		for (int i = 0; i < 7; ++i)
			data += DATA_HANDLER->getData(monday.addDays(i));
		return data;
	}
	case Month:
		return DATA_HANDLER->getData(date.year(), date.month());
	case Year:
		return DATA_HANDLER->getData(date.year());
	default:
		qWarning() << __FUNCTION__ << "faild! error time type:" << currentTimeType_;
		break;
	}
	return DataHandler::Data();
}

bool OneKeyboard::todayIsInTime(TimeType type, const QDate& date)
{
	QDate today = QDate::currentDate();
	switch (type)
	{
	case Day:
		return today == date;
	case Week:
	{
		int year1 = 0;
		int year2 = 0;
		return today.weekNumber(&year1) == date.weekNumber(&year2) && year1 == year2;
	}
	case Month:
		return today.month() == date.month() && today.year() == date.year();
	case Year:
		return today.year() == date.year();
	}
	return true;
}

void OneKeyboard::mousePressEvent(QMouseEvent* ev)
{
	pressPos_ = ev->pos();
	if (ui.widget_top->geometry().contains(pressPos_))
	{
		isPressed_ = true;
	}
}

void OneKeyboard::mouseMoveEvent(QMouseEvent* ev)
{
	if (isPressed_)
	{
		auto globalPos = ev->globalPos();
		move(globalPos - pressPos_);
	}
}

void OneKeyboard::mouseReleaseEvent(QMouseEvent* ev)
{
	isPressed_ = false;
}
